package org.lyl.taobao.controller;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.lyl.taobao.api.IUserService;
import org.lyl.taobao.api.entity.User;
import org.lyl.taobao.service.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.util.List;
import java.util.UUID;

/**
 * @Author: Re
 * @Date: 2021/4/12 22:19
 */

@WebServlet("/photo.do")
public class UploadPicturesServlet extends HttpServlet {
    private static final long serialVersionUID = 8525671995700987977L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (!ServletFileUpload.isMultipartContent(req)){
            return;
        }
        String uploadPath  = this.getServletContext().getRealPath("/upload");
        System.out.println("this的值为-->"+this);
        System.out.println("文件保存路径-->" + uploadPath);
        File uploadFile = new File(uploadPath);
        // 文件夹要是不存在那就再建一个
        if (!uploadFile.exists()) {
            uploadFile.mkdir();
        }
        // 如果文件大小超出预期大小则存在临时路径
        String tempPath = this.getServletContext().getRealPath("/temp");
        System.out.println("临时文件保存路径-->" + tempPath);
        File tempFile = new File(tempPath);
        if (!tempFile.exists()) {
            tempFile.mkdir();
        }
        // 处理上传的文件，一般需要通过流来获取，我们可以使用request.getInputStream(),原生态的文件上传流获取，十分麻烦
        //但是我们都建议使用Apache的文件上传组件来实现，common-fileupload,他需要依赖commons-io组件

        // 1. 创建DiskFileItemFactory对象: 处理文件上传路径或者大小限制的
        DiskFileItemFactory factory = getDiskFileItemFactory(tempFile);
        /*
         * 2. 获取ServletFileUpload
         * ServletFileUpload负责处理上传的文件数据，并将表单中个每个输入项封装成一个FileItem对象
         * 在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象
         * 所以，我们需要在进行解析工作前构造好DiskFileItemFactory对象
         * 通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性
         */

        ServletFileUpload upload = getServletFileUpload(factory);
        /*
         * 3.处理上传的文件
         */

        String msg = null;
        try {
            HttpSession session = req.getSession();
            User user = (User) session.getAttribute("user");
            msg = uploadParseRequest(upload,req,uploadPath);
            IUserService iUserService = new UserServiceImpl();
            iUserService.addPhoto(msg,user);
        } catch (FileUploadException e){
            e.printStackTrace();
        }
        // servlet请求转发消息
        req.setAttribute("msg",msg);
        req.getRequestDispatcher("homepage.jsp").forward(req,resp);
    }
    public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
        ServletFileUpload upload = new ServletFileUpload(factory);
        // 处理乱码
        upload.setHeaderEncoding("UTF-8");
        // 设置单个文件的最大值
        upload.setFileSizeMax(1024*1024*10);
        // 设置总共能够上传文件的大小
        upload.setSizeMax(1024*1024*10);
        return upload;
    }
    public static DiskFileItemFactory getDiskFileItemFactory(File file){
        // 通过该工厂设置一个缓冲区，当上传文件大于缓冲区时，将它放到临时文件中去
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 设置缓冲区大小为10M
        factory.setSizeThreshold(1024*1024*10);
        // 临时目录的保存目录
        factory.setRepository(file);
        return factory;
    }
    public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest request,String uploadPath) throws FileUploadException,IOException{
        String msg = "";
        // 3.把前端请求解析，封装成一个FileItem对象
        List<FileItem> fileItems = upload.parseRequest(request);
        for (FileItem fileItem:fileItems) {
            // 判断上传的文件是普通的表单还是带文件的表单
            if (fileItem.isFormField()){
                // getFileName指的是前端表单控件的name
                String name = fileItem.getFieldName();
                // 处理乱码
                String value = fileItem.getString("UTf-8");
                System.out.println(name + ":" + value);
            } else {
                // 判断它是上传的文件
                //文件处理

                // 拿到文件名
                String uploadFileName = fileItem.getName();
                System.out.println("上传的文件名：" + uploadFileName);
                if ("".equals(uploadFileName.trim())||uploadFileName == null) {
                    continue;
                }
                // 获得上传文件名
                String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/")+1);
                // 获得文件后缀名
                String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1);
                 /* 如果文件后缀名fileExtName不是我们需要的就直接return，不处理，并告诉用户文件类型不对
                 */

                System.out.println("文件信息[文件名：" + fileName + "--文件类型：" + fileExtName);
                 /*可以使用UUID（唯一识别通用码），保证文件名的唯一
                 * UUID.randomUUID(),随机生一个唯一识别的通用码
                 * 但是生成的UUID没有办法往数据库里存
                 */

                String uuidPath = UUID.randomUUID().toString();
                //文件处理完毕

                // 存到哪？ uploadPath
                // 文件真实存放的路径 realPath
                String realPath = uploadPath + "/" +uuidPath;
                System.out.println(realPath);
                //给每个文件创建一个对应文件夹
                File realPathFile = new File(realPath);
                if (!realPathFile.exists()){
                    realPathFile.mkdir();
                }
                //存放地址完毕

                // 获得文件上传的流
                InputStream inputStream = fileItem.getInputStream();

                // 创建一个文件输出流
                // realPath = 真实的文件夹
                FileOutputStream fos = new FileOutputStream(realPath+"/"+fileName);
                // 创建一个缓冲区
                byte[] buffer = new byte[1024*1024];
                // 判断是否读取完毕
                int len = 0;
                while((len = inputStream.read(buffer)) > 0){
                    fos.write(buffer,0,len);
                }
                //关闭流
                fos.close();
                inputStream.close();

                msg = uuidPath + "/" + fileName;
                // 上传成功清除临时文件
                fileItem.delete();
            }
        }
        return msg;
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
